package com.ok.common.utils

import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkInfo
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log

@SuppressLint("StaticFieldLeak")
object NetworkMonitor {

    private const val TAG = "NetworkMonitor"

    private var context: Context? = null
    private var listener: NetworkListener? = null
    private var connectivityManager: ConnectivityManager? = null
    private var isConnected = false
    private var networkCallbackRegistered = false
    private val mHandler = Handler(Looper.getMainLooper())

    private val connectivityReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
                updateNetworkConnection()
            }
        }
    }

    private val networkCallback = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                isConnected = true
                mHandler.post {
                    listener?.onNetworkConnected()
                }
            }

            override fun onLost(network: Network) {
                isConnected = false
                mHandler.post {
                    listener?.onNetworkDisconnected()
                }
            }
        }
    } else null

    fun start(ctx: Context, listener: NetworkListener) {
        this.context = ctx.applicationContext
        this.listener = listener
        connectivityManager = ctx.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // For API 24+ we can use registerDefaultNetworkCallback which automatically handles all networks.
            networkCallback?.let { connectivityManager?.registerDefaultNetworkCallback(it) }
        } else {
            // For lower versions, we still need to listen for broadcasts.
            ctx.registerReceiver(connectivityReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
        }
        networkCallbackRegistered = true
        updateNetworkConnection()
    }

    fun stop() {
        if (networkCallbackRegistered) {
            try {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    if (networkCallback != null) {
                        connectivityManager?.unregisterNetworkCallback(networkCallback)
                    }
                } else {
                    context?.unregisterReceiver(connectivityReceiver)
                }
            } catch (e: IllegalArgumentException) {
                Log.e(TAG, "Error unregistering network callback/receiver", e)
            } finally {
                networkCallbackRegistered = false
            }
        }
        listener = null
        context = null
        connectivityManager = null
    }

    private fun updateNetworkConnection() {
        connectivityManager?.run {
            val activeNetwork: NetworkInfo? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                activeNetworkInfo
            } else {
                @Suppress("DEPRECATION") activeNetworkInfo
            }
            val isConnectedNow = activeNetwork?.isConnectedOrConnecting ?: false
            if (isConnectedNow != isConnected) {
                isConnected = isConnectedNow
                if (isConnected) {
                    mHandler.post {
                        listener?.onNetworkConnected()
                    }
                } else {
                    mHandler.post {
                        listener?.onNetworkDisconnected()
                    }
                }
            }
        }
    }
}

interface NetworkListener {
    fun onNetworkConnected()
    fun onNetworkDisconnected()
}

